package com.flyiu.data.consistency.schedual;

import static com.flyiu.data.consistency.model.DistributedTransactionState.INIT;
import static com.flyiu.data.consistency.model.DistributedTransactionState.PRE_CANCEL;
import static com.flyiu.data.consistency.model.DistributedTransactionState.PRE_COMMIT;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.Predicate;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.flyiu.data.consistency.model.DistributedTransactionInstance;
import com.flyiu.data.consistency.repository.DistributedTransactionInstanceRepository;
import com.flyiu.data.consistency.service.RecoverService;

//@Component
public class RecoverSchedual {

    @Autowired
    private DistributedTransactionInstanceRepository instanceRepository;
    @Autowired
    private RecoverService                           revocerService;

    /**
     * 获取多长时间以后的失败信息
     * 
     * @return
     */
    private Date getUpdateDate(int type,int value) {
        Calendar c = Calendar.getInstance();
        c.add(type ,value);
        return c.getTime();
    }

    @Async
    public void recover(DistributedTransactionInstance distributedTransactionInstance) {
        revocerService.recoverOne(distributedTransactionInstance);
    }

    @Scheduled(fixedDelay = 50000)
    @Transactional()
    public void executeTenMin() {
        Page<DistributedTransactionInstance> instancePage = instanceRepository.findAll((root, query, cb) -> {
            Predicate statePredicate = root.get("transactionState").in(INIT, PRE_CANCEL, PRE_COMMIT);
            Predicate datePredicate = cb.lessThan(root.get("updateTime"), getUpdateDate(Calendar.SECOND,-20));
            Predicate datePredicate2 = cb.greaterThan(root.get("updateTime"), getUpdateDate(Calendar.MINUTE,-10));
            return cb.and(statePredicate, datePredicate,datePredicate2);
        }, PageRequest.of(0, 20, Sort.by(org.springframework.data.domain.Sort.Order.desc("createTime"))));
        List<DistributedTransactionInstance> instanceList = instancePage.getContent();
        instanceList.forEach(this::recover);
    }

    /**
     * 间隔1小时
     */
    @Scheduled(fixedDelay = 1000 * 60 * 10)
    @Transactional()
    public void executeAHour() {
        Page<DistributedTransactionInstance> instancePage = instanceRepository.findAll((root, query, cb) -> {
            Predicate statePredicate = root.get("transactionState").in(INIT, PRE_CANCEL, PRE_COMMIT);
            Predicate datePredicate = cb.lessThan(root.get("updateTime"), getUpdateDate(Calendar.SECOND,-20));
            Predicate datePredicate2 = cb.greaterThan(root.get("updateTime"), getUpdateDate(Calendar.HOUR_OF_DAY,-1));
            return cb.and(statePredicate, datePredicate,datePredicate2);
        }, PageRequest.of(0, 20, Sort.by(org.springframework.data.domain.Sort.Order.desc("createTime"))));
        List<DistributedTransactionInstance> instanceList = instancePage.getContent();
        instanceList.forEach(this::recover);
    }

    @Scheduled(fixedDelay = 1000 * 60 * 60)
    @Transactional()
    public void executeADay() {
        Page<DistributedTransactionInstance> instancePage = instanceRepository.findAll((root, query, cb) -> {
            Predicate statePredicate = root.get("transactionState").in(INIT, PRE_CANCEL, PRE_COMMIT);
            Predicate datePredicate = cb.lessThan(root.get("updateTime"), getUpdateDate(Calendar.SECOND,-20));
            Predicate datePredicate2 = cb.greaterThan(root.get("updateTime"), getUpdateDate(Calendar.DATE,-1));
            return cb.and(statePredicate, datePredicate,datePredicate2);
        }, PageRequest.of(0, 20, Sort.by(org.springframework.data.domain.Sort.Order.desc("createTime"))));
        List<DistributedTransactionInstance> instanceList = instancePage.getContent();
        instanceList.forEach(this::recover);
    }
}
